/**
 * @file src/datatypes/Map3D.java
 */
package datatypes;

/** imports */
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.Writer;
//import java.util.Collections;
//import java.util.Comparator;
import java.util.Scanner;
import java.util.Vector;

public class Map3D
{
	/** all stored points */
	private Vector<Point3D> mPoints;
	
	/** sorted according to x values */
	// private Vector<Point3D> mAscendingOrderX;

	/** sorted according to y values */
	// private Vector<Point3D> mAscendingOrderY;
	
	/**
	 * Default constructor
	 */
	public Map3D()
	{
		mPoints = new Vector<Point3D>();
	}

	/** Getter */
	public Point3D get(int i)
	{
		if (0 <= i && i < mPoints.size()) { return mPoints.get(i); }
		return null;
	}
	
	public int getSize() { return mPoints.size(); }
	
	
	/**
	 * read in 3D map
	 * 
	 * @param fn Location of file
	 */
	public void read(String fn) throws Exception
	{
		/** clear old world */
		mPoints.clear();
		
        /** Find out system specific line separator */
        // final String NEWLINE = System.getProperty("line.separator");
        
        /** instantiate the actual scanner and input stream */
        Scanner scanner = new Scanner(new FileInputStream(fn));
        
        /** start reading file */
        try {
            
        	while (true) {
        		
                /** first integer, X */
                int x = scanner.hasNextInt() ? scanner.nextInt() : Integer.MAX_VALUE;
                if (x == Integer.MAX_VALUE) { 
                	/** apparently reached end of file */
                	break;
                }
                
                /** second integer, Y */
                int y = scanner.hasNextInt() ? scanner.nextInt() : Integer.MAX_VALUE;
                if (y == Integer.MAX_VALUE) { throw new Exception("Y value not provided!"); }

                /** third float, Z  */
                float z = scanner.hasNextFloat() ? scanner.nextFloat() : Float.MAX_VALUE;
                if (z == Float.MAX_VALUE) { throw new Exception("Z value not provided!"); }
                
                /** store data */
                mPoints.addElement(new Point3D(x, y, z));

                /** go to next line */
                if (scanner.hasNextLine()) {
                	scanner.nextLine();
                } else {
                	break;
                }
        	} // while(true)
        } catch (Exception e) {
        	System.out.println(e.toString());
        } finally {
            /** close scanner when finished */
            scanner.close();
        } // finally
        
        /** trim vector */
        mPoints.trimToSize();
        
        generateNeighborhood();

	} // read(string fn)
	
	/**
	 * Compute neighborhood of all points
	 */
	private void generateNeighborhood()
	{	
		/**
		 *  stencil:
		 *  
		 *  (00) 01 (02)
		 *   10  11  12
		 *  (20) 21 (22)
		 *
		 * where 11 is a given point and all others are neighbors 
		 */
		for (Point3D p: mPoints) {
			int x0 = p.getX() - 1;
			int x1 = p.getX();
			int x2 = p.getX() + 1;
			
			int y0 = p.getY() - 1;
			int y1 = p.getY();
			int y2 = p.getY() + 1;

			for (Point3D q: mPoints) {

				boolean isNeighbor = false;
				
				
				/** 3x3 stencil without center */
//				if (q.getX() == x0) {								 /** x left */
//					if (q.getY() == y0) { 			/** y up */
//						isNeighbor = true;
//					} else if (q.getY() == y1) {	/** y middle */
//						isNeighbor = true;
//					} else if (q.getY() == y2) {	/** y low */
//						isNeighbor = true;
//					}
//				} else if (q.getX() == x1) { 						/** x middle */
//					if (q.getY() == y0) {			/** y up */
//						isNeighbor = true;
//					} else if (q.getY() == y2) {	/** y low */
//						isNeighbor = true;
//					}
//				} else if (q.getX() == x2) { 						/** x right */
//					if (q.getY() == y0) {			/** y up */
//						isNeighbor = true;
//					} else if (q.getY() == y1) {	/** y middle */
//						isNeighbor = true;
//					} else if (q.getY() == y2) {	/** y low */
//						isNeighbor = true;
//					}
//				} // if
				
				/**
				 *  stencil:
				 *  
				 *       01 
				 *   10  11  12
				 *       21 
				 *
				 * where 11 is a given point and all others are neighbors 
				 */
				if (q.getX() == x0 && q.getY() == y1) { 		// x = left, y = middle
					
					isNeighbor = true;
					
				} else if (q.getX() == x1) {
				
					if (q.getY() == y0) {						// x = middle, y = up
						isNeighbor = true;
					} else if (q.getY() == y2) {				// x = middle, y = down
						isNeighbor = true;
					}
					
				} else if (q.getX() == x2 && q.getY() == y1) { 	// x = right, y = middle
					
					isNeighbor = true;
					
				}
				
				/** add if neighbor */
				if (isNeighbor) { p.addNeighbor(q); }
				
			} // for each point q

			/** trim to size */
			p.getNeighbors().trimToSize();
			
		} // for each point p
		
	} // generateNeighborhood()

	
	/**
	 * Override toString()
	 * 
	 * @return String representation of a Map3D
	 */
	public String toString()
	{
		String result = "Map = {\n";
		for (int i = 0; i < mPoints.size() - 1; ++i) {
			result += "\t" + mPoints.get(i).toString() + ",\n";
		}
		result += "\t" + mPoints.get(mPoints.size() - 1).toString() + "  }";
		return result;
	}

	

	/**
	 * Write a sequence to a file
	 *
	 * @param fn File to write
	 * @param seq Sequence to write
	 */
	public static String writeSequenceToFile(String fn, Vector<Point3D> seq) throws Exception
	{
		/** use buffering */
		Writer output = new BufferedWriter(new FileWriter(fn));
		
		String result = "";

		try {
		    String NL = System.getProperty("line.separator");
			
		    for (Point3D a: seq) {
		    	if (a.getX() == Integer.MAX_VALUE) { 
		    		result += NL;
		    	} else {
		    		result += a.getX() + " " + a.getY() + " " + a.getZ() + NL;
		    	}
			}
			/** FileWriter always assumes default encoding is OK! */
			output.write(result);
			
		} finally {
			output.close();
		}
		
		return result;
	} // writeSequenceToFile(String fn, Vector<Point3D> seq)
	
	
} // class Map3D

